/*
     -------------------------------------------------------------------
    |                                                                                                              |
    |    Stack Class                                                                                          |
    |    ==============================================      |
    |    This Stack has been implemented with templates to allow it                       |
    |    to accomodate virtually any data type, and the size of the                          |
    |    Stack is determined dynamically at runtime.                                              |
    |                                                                                                               |
    |    There is also a new function: peek(), which, given a whole                           |
    |    number 'Depth', returns the Stack element which is 'Depth'                           |
    |    levels from the top.                                                                                 |
    |                                                                                                                |
     -------------------------------------------------------------------
*/

#ifndef __STACK_H__
#define __STACK_H__

#include <assert.h>

template <class Elem>

class Stack 
{
public:
	Stack(int MaxSize = 500);
	Stack(const Stack<Elem> &otherStack);
	~Stack(void);

	inline void push(Elem &item);  // Adds Item to the top  
	inline  Elem pop();             // Returns Item from the top 
	inline const Elem& peek(int depth) const; // Peek a depth downwards  
	inline int size() const;
	inline bool empty() const;

	
private:
	Elem *m_data;
	int CurrElemNum;
	const int MAX_SIZE;
	
};


//-------------------------------------------------  
//Implementation of Stack Class:
//--------------------------------------------------

template <class Elem>
Stack<Elem>::Stack(int MaxSize):MAX_SIZE(MaxSize)
{
	m_data = new Elem[MaxSize];
	CurrElemNum = 0;
}

template <class Elem>
Stack<Elem>::Stack(const Stack<Elem>& otherStack) :
				MAX_SIZE(otherStack.MAX_SIZE)
{
	CurrElemNum = otherStack.CurrElemNum;
	m_data = new Elem[MAX_SIZE];
}
				
template <class Elem>
Stack<Elem>::~Stack()
{
	delete[] m_data;
}

template <class Elem>
inline void Stack<Elem>::push(Elem &item)
{
	assert(CurrElemNum < MAX_SIZE);
	m_data[CurrElemNum++] = item;
}

template <class Elem>
inline Elem Stack<Elem>::pop()
{
	assert(CurrElemNum > 0);

	return m_data[--CurrElemNum];
}

template <class Elem>
inline const Elem& Stack<Elem>::peek(int depth) const
{
	// Error Check: Make sure the depth doesn't exceed the number of elements
	assert(CurrElemNum > depth);

	return m_data[CurrElemNum - (depth+1)];
}

template <class Elem>
inline int Stack<Elem>::size() const
{
	return CurrElemNum;
}

template <class Elem>
inline bool Stack<Elem>::empty() const
{
	return (CurrElemNum == 0);
}

#endif  //__STACK_H__
